<!DOCTYPE html>

<html>
<head>
  <title>repl.coffee</title>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
  <link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
  <div id="container">
    <div id="background"></div>
    
      <ul id="jump_to">
        <li>
          <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
          <a class="small" href="javascript:void(0);">+</a>
          <div id="jump_wrapper">
          <div id="jump_page">
            
              
              <a class="source" href="browser.html">
                browser.coffee
              </a>
            
              
              <a class="source" href="cake.html">
                cake.coffee
              </a>
            
              
              <a class="source" href="coffee-script.html">
                coffee-script.coffee
              </a>
            
              
              <a class="source" href="command.html">
                command.coffee
              </a>
            
              
              <a class="source" href="grammar.html">
                grammar.coffee
              </a>
            
              
              <a class="source" href="helpers.html">
                helpers.coffee
              </a>
            
              
              <a class="source" href="index.html">
                index.coffee
              </a>
            
              
              <a class="source" href="lexer.html">
                lexer.coffee
              </a>
            
              
              <a class="source" href="nodes.html">
                nodes.coffee
              </a>
            
              
              <a class="source" href="optparse.html">
                optparse.coffee
              </a>
            
              
              <a class="source" href="repl.html">
                repl.coffee
              </a>
            
              
              <a class="source" href="rewriter.html">
                rewriter.coffee
              </a>
            
              
              <a class="source" href="scope.html">
                scope.litcoffee
              </a>
            
              
              <a class="source" href="sourcemap.html">
                sourcemap.litcoffee
              </a>
            
          </div>
        </li>
      </ul>
    
    <ul class="sections">
        
          <li id="title">
              <div class="annotation">
                  <h1>repl.coffee</h1>
              </div>
          </li>
        
        
        
        <li id="section-1">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-1">&#182;</a>
              </div>
              
            </div>
            
            <div class="content"><div class='highlight'><pre>fs = require <span class="string">'fs'</span>
path = require <span class="string">'path'</span>
vm = require <span class="string">'vm'</span>
nodeREPL = require <span class="string">'repl'</span>
CoffeeScript = require <span class="string">'./coffee-script'</span>
{merge, prettyErrorMessage} = require <span class="string">'./helpers'</span>

replDefaults =
  prompt: <span class="string">'coffee&gt; '</span>,
  historyFile: path.join process.env.HOME, <span class="string">'.coffee_history'</span> <span class="keyword">if</span> process.env.HOME
  historyMaxInputSize: <span class="number">10240</span>
  eval: (input, context, filename, cb) -&gt;</pre></div></div>
            
        </li>
        
        
        <li id="section-2">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-2">&#182;</a>
              </div>
              <p>XXX: multiline hack.
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    input = input.replace <span class="regexp">/\uFF00/g</span>, <span class="string">'\n'</span></pre></div></div>
            
        </li>
        
        
        <li id="section-3">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-3">&#182;</a>
              </div>
              <p>Node&#39;s REPL sends the input ending with a newline and then wrapped in
parens. Unwrap all that.
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    input = input.replace <span class="regexp">/^\(([\s\S]*)\n\)$/m</span>, <span class="string">'$1'</span></pre></div></div>
            
        </li>
        
        
        <li id="section-4">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-4">&#182;</a>
              </div>
              <p>Require AST nodes to do some AST manipulation.
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    {Block, Assign, Value, Literal} = require <span class="string">'./nodes'</span>

    <span class="keyword">try</span></pre></div></div>
            
        </li>
        
        
        <li id="section-5">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-5">&#182;</a>
              </div>
              <p>Generate the AST of the clean input.
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      ast = CoffeeScript.nodes input</pre></div></div>
            
        </li>
        
        
        <li id="section-6">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-6">&#182;</a>
              </div>
              <p>Add assignment to <code>_</code> variable to force the input to be an expression.
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      ast = <span class="keyword">new</span> Block [
        <span class="keyword">new</span> Assign (<span class="keyword">new</span> Value <span class="keyword">new</span> Literal <span class="string">'_'</span>), ast, <span class="string">'='</span>
      ]
      js = ast.compile bare: <span class="literal">yes</span>, locals: Object.keys(context)
      cb <span class="literal">null</span>, vm.runInContext(js, context, filename)
    <span class="keyword">catch</span> err
      cb prettyErrorMessage(err, filename, input, <span class="literal">yes</span>)

<span class="function"><span class="title">addMultilineHandler</span></span> = (repl) -&gt;
  {rli, inputStream, outputStream} = repl

  multiline =
    enabled: <span class="literal">off</span>
    initialPrompt: repl.prompt.replace <span class="regexp">/^[^&gt; ]*/, (x) -&gt; x.replace /./g</span>, <span class="string">'-'</span>
    prompt: repl.prompt.replace <span class="regexp">/^[^&gt; ]*&gt;?/, (x) -&gt; x.replace /./g</span>, <span class="string">'.'</span>
    buffer: <span class="string">''</span></pre></div></div>
            
        </li>
        
        
        <li id="section-7">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-7">&#182;</a>
              </div>
              <p>Proxy node&#39;s line listener
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  nodeLineListener = rli.listeners(<span class="string">'line'</span>)[<span class="number">0</span>]
  rli.removeListener <span class="string">'line'</span>, nodeLineListener
  rli.<span class="literal">on</span> <span class="string">'line'</span>, (cmd) -&gt;
    <span class="keyword">if</span> multiline.enabled
      multiline.buffer += <span class="string">"<span class="subst">#{cmd}</span>\n"</span>
      rli.setPrompt multiline.prompt
      rli.prompt <span class="literal">true</span>
    <span class="keyword">else</span>
      nodeLineListener cmd
    <span class="keyword">return</span></pre></div></div>
            
        </li>
        
        
        <li id="section-8">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-8">&#182;</a>
              </div>
              <p>Handle Ctrl-v
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  inputStream.<span class="literal">on</span> <span class="string">'keypress'</span>, (char, key) -&gt;
    <span class="keyword">return</span> <span class="keyword">unless</span> key <span class="keyword">and</span> key.ctrl <span class="keyword">and</span> <span class="keyword">not</span> key.meta <span class="keyword">and</span> <span class="keyword">not</span> key.shift <span class="keyword">and</span> key.name <span class="keyword">is</span> <span class="string">'v'</span>
    <span class="keyword">if</span> multiline.enabled</pre></div></div>
            
        </li>
        
        
        <li id="section-9">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-9">&#182;</a>
              </div>
              <p>allow arbitrarily switching between modes any time before multiple lines are entered
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      <span class="keyword">unless</span> multiline.buffer.match <span class="regexp">/\n/</span>
        multiline.enabled = <span class="keyword">not</span> multiline.enabled
        rli.setPrompt repl.prompt
        rli.prompt <span class="literal">true</span>
        <span class="keyword">return</span></pre></div></div>
            
        </li>
        
        
        <li id="section-10">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-10">&#182;</a>
              </div>
              <p>no-op unless the current line is empty
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      <span class="keyword">return</span> <span class="keyword">if</span> rli.line? <span class="keyword">and</span> <span class="keyword">not</span> rli.line.match <span class="regexp">/^\s*$/</span></pre></div></div>
            
        </li>
        
        
        <li id="section-11">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-11">&#182;</a>
              </div>
              <p>eval, print, loop
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      multiline.enabled = <span class="keyword">not</span> multiline.enabled
      rli.line = <span class="string">''</span>
      rli.cursor = <span class="number">0</span>
      rli.output.cursorTo <span class="number">0</span>
      rli.output.clearLine <span class="number">1</span></pre></div></div>
            
        </li>
        
        
        <li id="section-12">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-12">&#182;</a>
              </div>
              <p>XXX: multiline hack
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      multiline.buffer = multiline.buffer.replace <span class="regexp">/\n/g</span>, <span class="string">'\uFF00'</span>
      rli.emit <span class="string">'line'</span>, multiline.buffer
      multiline.buffer = <span class="string">''</span>
    <span class="keyword">else</span>
      multiline.enabled = <span class="keyword">not</span> multiline.enabled
      rli.setPrompt multiline.initialPrompt
      rli.prompt <span class="literal">true</span>
    <span class="keyword">return</span></pre></div></div>
            
        </li>
        
        
        <li id="section-13">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-13">&#182;</a>
              </div>
              <p>Store and load command history from a file
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre><span class="function"><span class="title">addHistory</span></span> = (repl, filename, maxSize) -&gt;
  lastLine = <span class="literal">null</span>
  <span class="keyword">try</span></pre></div></div>
            
        </li>
        
        
        <li id="section-14">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-14">&#182;</a>
              </div>
              <p>Get file info and at most maxSize of command history
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    stat = fs.statSync filename
    size = Math.min maxSize, stat.size</pre></div></div>
            
        </li>
        
        
        <li id="section-15">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-15">&#182;</a>
              </div>
              <p>Read last <code>size</code> bytes from the file
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    readFd = fs.openSync filename, <span class="string">'r'</span>
    buffer = <span class="keyword">new</span> Buffer(size)
    fs.readSync readFd, buffer, <span class="number">0</span>, size, stat.size - size</pre></div></div>
            
        </li>
        
        
        <li id="section-16">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-16">&#182;</a>
              </div>
              <p>Set the history on the interpreter
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    repl.rli.history = buffer.toString().split(<span class="string">'\n'</span>).reverse()</pre></div></div>
            
        </li>
        
        
        <li id="section-17">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-17">&#182;</a>
              </div>
              <p>If the history file was truncated we should pop off a potential partial line
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    repl.rli.history.pop() <span class="keyword">if</span> stat.size &gt; maxSize</pre></div></div>
            
        </li>
        
        
        <li id="section-18">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-18">&#182;</a>
              </div>
              <p>Shift off the final blank newline
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>    repl.rli.history.shift() <span class="keyword">if</span> repl.rli.history[<span class="number">0</span>] <span class="keyword">is</span> <span class="string">''</span>
    repl.rli.historyIndex = -<span class="number">1</span>
    lastLine = repl.rli.history[<span class="number">0</span>]

  fd = fs.openSync filename, <span class="string">'a'</span>

  repl.rli.addListener <span class="string">'line'</span>, (code) -&gt;
    <span class="keyword">if</span> code <span class="keyword">and</span> code.length <span class="keyword">and</span> code <span class="keyword">isnt</span> <span class="string">'.history'</span> <span class="keyword">and</span> lastLine <span class="keyword">isnt</span> code</pre></div></div>
            
        </li>
        
        
        <li id="section-19">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-19">&#182;</a>
              </div>
              <p>Save the latest command in the file
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>      fs.write fd, <span class="string">"<span class="subst">#{code}</span>\n"</span>
      lastLine = code

  repl.rli.<span class="literal">on</span> <span class="string">'exit'</span>, -&gt; fs.close fd</pre></div></div>
            
        </li>
        
        
        <li id="section-20">
            <div class="annotation">
              
              <div class="pilwrap ">
                <a class="pilcrow" href="#section-20">&#182;</a>
              </div>
              <p>Add a command to show the history stack
</p>

            </div>
            
            <div class="content"><div class='highlight'><pre>  repl.commands[<span class="string">'.history'</span>] =
    help: <span class="string">'Show command history'</span>
    action: -&gt;
      repl.outputStream.write <span class="string">"<span class="subst">#{repl.rli.history[..].reverse().join '\n'}</span>\n"</span>
      repl.displayPrompt()

module.exports =
  start: (opts = {}) -&gt;
    [major, minor, build] = process.versions.node.split(<span class="string">'.'</span>).map (n) -&gt; parseInt(n)

    <span class="keyword">if</span> major <span class="keyword">is</span> <span class="number">0</span> <span class="keyword">and</span> minor &lt; <span class="number">8</span>
      console.warn <span class="string">"Node 0.8.0+ required for CoffeeScript REPL"</span>
      process.exit <span class="number">1</span>

    opts = merge replDefaults, opts
    repl = nodeREPL.start opts
    repl.<span class="literal">on</span> <span class="string">'exit'</span>, -&gt; repl.outputStream.write <span class="string">'\n'</span>
    addMultilineHandler repl
    addHistory repl, opts.historyFile, opts.historyMaxInputSize <span class="keyword">if</span> opts.historyFile
    repl</pre></div></div>
            
        </li>
        
    </ul>
  </div>
</body>
</html>
